'''
Created on 2009-6-13

@author: roamer
'''
from codeprocess import *
from analysis import *
import Util
import Image,os

class MainProcess(object):
    def __init__(self,code):
        self.__parser = ParseCode.ParseCode(code)
        words = Statistics.Statistics().RestoreResult()
        bases = Statistics.BaseProcess().RestoreResult()
        params = Params.Params().RestoreResultFromFile()
        self.Data = {"words" : words[Setting.Setting["ImgKey"]],"words_max_min" : words[Setting.Setting["ImgKey_Max_Min"]],"bases" : bases,"params" : params}
        
    def Parse(self):
        bases = self.__parser.Parse()
        base_count = len(bases)
        params = []
        for i in range(0,base_count):
            key = bases[i][0]
            close_codes = self.__getClosedParams(key, i, base_count)
            param_bak = list(close_codes)
            for j in range(len(close_codes) - 1,-1,-1):
                x1,y1,x2,y2 = self.Data["bases"][key]
                a,c,b,d = close_codes[j]
                x1 = a * x1 + c
                y1 = b * y1 + d
                x2 = a * x2 + c
                y2 = b * y2 + d
                a,b,c,d = bases[i][1]
                if a > x1 or c + a < x2 or b > y1 or d + b < y2:
                    del close_codes[j]
            if len(close_codes) == 0:
                print "No filters were applied to %s,parameters count: %d" % (key,len(param_bak))
                close_codes = param_bak
            print "Candidate count for %s: %d" % (key,len(close_codes))
            params.append((key,bases[i][1],close_codes))
        ret = []
        for param in params:
            ret = self.__getPerm(ret, param)
        final_result_set = []
        print "Total candidates:",len(ret)
        for word in ret:
            a,b,c,d =  self.__getIntersections(word)
            im = self.CreateImage(word)            
            imggem = self.__getImgParam(im)
            max_min = self.Data['words_max_min'][str((int(imggem[1][0] / Setting.Setting["Step"]) + 1) * Setting.Setting["Step"])]
            inArea = 0
            if imggem[1][1] >= max_min[0][0] and imggem[1][1] <= max_min[1][0] and imggem[1][2] >= max_min[0][1] and imggem[1][2] >= max_min[1][1]:
                inArea = 0
            else:
                inArea = (15.5 - imggem[1][1])**2 + (15.5 - imggem[1][2])**2
            final_result_set.append((a,b,c,d,inArea,imggem[1][0],im));
        final_result_set.sort(cmp=MainProcess.__sortResult)
        result_len = len(final_result_set)
        for i in range(result_len - 1,0,-1):
            del final_result_set[i]
        if len(final_result_set) == 1:
            final_result_set[0][6].show()
            del final_result_set[0]
        else:
            print "No result!"
            
    @staticmethod
    def __sortResult(x,y):
        point = 0
        if x[0] > y[0]:
            point += -25
        elif x[0] < y[0]:
            point += 25
        if x[1] > y[1]:
            point += -30
        elif x[1] < y[1]:
            point += 30
        if x[2] > y[2]:
            point += 10
        elif x[2] < y[2]:
            point += -10
        if x[3] > y[3]:
            point += -100
        elif x[3] < y[3]:
            point += 100
        if x[4] > y[4]:
            point += -5
        elif x[4] < y[4]:
            point += 5
        if x[5] > y[5]:
            point += 50
        elif x[5] < y[5]:
            point += -50
        return -point
    
    
    def __getImgParam(self,image):
        black_count = 0;
        x_sum = 0;
        y_sum = 0;
        x_size,y_size = image.size
        minx = x_size
        maxx = 0
        miny = y_size
        maxy = 0
        for i in range(0,x_size):
            for j in range(0,y_size):
                pixel = image.getpixel((i,j))
                if isinstance(pixel, tuple):
                    pixel = sum(pixel)
                if pixel < 150:
                    black_count += 1
                    x_sum += i
                    y_sum += j
                    if(minx > i):
                        minx = i
                    if(maxx < i):
                        maxx = i
                    if(miny > j):
                        miny = j
                    if(maxy < j):
                        maxy = j
        if black_count == 0:
            black_count = 1        
        return ((minx,miny,maxx,maxy),(black_count,float(x_sum) / float(black_count),float(y_sum) / float(black_count)))
    
    def __getIntersections(self,item):
        if len(item) < 2:
            return 0,0,1024,False
        comb = Util.Util.Combination(item, 2)
        ret = []
        for x,y in comb:
            com_area = 0
            com_point = 0
            total_area = 0
            outside = False
            a,b,c,d = self.Data['bases'][x[0]]
            a1,b1,c1,d1 = self.Data['bases'][y[0]]
            a = a * x[1][0] + x[1][1]
            b = b * x[1][2] + x[1][3]
            c = c * x[1][0] + x[1][1]
            d = d * x[1][2] + x[1][3]
            a1 = a1 * y[1][0] + y[1][1]
            b1 = b1 * y[1][2] + y[1][3]
            c1 = c1 * y[1][0] + y[1][1]
            d1 = d1 * y[1][2] + y[1][3]
            total_area = (c - a) * (d - b) + (c1 - a1) * (d1 - b1)
            outside = any(map(lambda x: x < 0 or x >= 32,(a,b,c,d,a1,b1,c1,d1)))
            intersection = (int(max(a,a1)) - 1,int(max(b,b1)) - 1,int(min(c,c1)) + 1,int(min(d,d1)) + 1)
            if intersection[0] >= intersection[2] or intersection[1] >= intersection[3]:
                com_area = 0
            else:
                com_area = (intersection[2] - intersection[0]) * (intersection[3] - intersection[1])
            ima = Image.open(Setting.Setting['BaseFolder'] + os.sep + x[0] + Setting.Setting['ImgExt'])
            imb = Image.open(Setting.Setting['BaseFolder'] + os.sep + y[0] + Setting.Setting['ImgExt'])
            imx = Image.new("L",(32,32),0xFFFFFF)
            imy = Image.new("L",(32,32),0xFFFFFF)
            for i in range(0,32):
                for j in range(0,32):
                    pixelx = ima.getpixel((i,j))
                    pixely = imb.getpixel((i,j))
                    if(isinstance(pixelx, tuple)):
                        pixelx = sum(pixelx)
                    if(isinstance(pixely, tuple)):
                        pixely = sum(pixely)
                    i1 = int(i * x[1][0] + x[1][1])
                    j1 = int(j * x[1][2] + x[1][3])
                    i2 = int(i * y[1][0] + y[1][1])
                    j2 = int(j * y[1][2] + y[1][3])
                    if pixelx < 150:
                        if i1 >= 0 and i1 < 32 and j1 >= 0 and j1 < 32:
                            imx.putpixel((i1,j1),pixelx)
                    if pixely < 150:
                        if i2 >= 0 and i2 < 32 and j2 >= 0 and j2 < 32:
                            imy.putpixel((i2,j2),pixely)
            for i in range(intersection[0],intersection[2]):
                for j in range(intersection[1],intersection[3]):
                    if i >= 0 and i < imx.size[0] and j >= 0 and j < imx.size[1] and i < imy.size[0] and j < imy.size[1]:
                        pixelx = imx.getpixel((i,j))
                        pixely = imy.getpixel((i,j))
                        if(isinstance(pixelx, tuple)):
                            pixelx = sum(pixelx)
                        if(isinstance(pixely, tuple)):
                            pixely = sum(pixely)
                        if pixelx < 150 and pixely < 150:
                            com_point += 1
            ret.append((com_area,com_point,total_area,outside))
            del ima,imb,imx,imy
        interset_area,intersect_point,total_area,outside = reduce(lambda x,y: (x[0]+y[0],x[1]+y[1],x[2]+y[2],x[3] or y[3]), ret)
        return (interset_area,intersect_point,int(total_area / 2 - interset_area),outside)
        
    def CreateImage(self,param):
        im = Image.new("L",(32,32),0xFFFFFF)
        for item in param:
            img = Image.open(Setting.Setting['BaseFolder'] + os.sep + item[0] + Setting.Setting['ImgExt'])
            x,y = img.size
            for i in range(0,x):
                for j in range(0,y):
                    pixel = img.getpixel((i,j))
                    if(isinstance(pixel,tuple)):
                        pixel = sum(pixel)
                    if pixel > 255:
                        pixel = 255
                    a = int(i * item[1][0] + item[1][1])
                    b = int(j * item[1][2] + item[1][3])
                    if a > 0 and a < x and b > 0 and b < y:
                        if im.getpixel((a,b)) > pixel:
                            im.putpixel((a,b),pixel)
            del img
        return im
        
    def __getPerm(self,ret,items):
        a = []
        key = items[0]
        for item in items[2]:
            if len(ret) == 0:
                a.append([(key,item)])
            else:
                for i in ret:
                    i = list(i)
                    i.append((key,item))
                    a.append(i)
        return a
    
    def __getClosedParams(self,code,order,total):
        codes = self.Data["params"][code]
        closed_codes = filter(lambda x : x[1] == order and x[2] == total, codes)
        if(len(closed_codes) == 0):
            closed_codes = codes
        ret = []
        for i in closed_codes:
            ps = i[0].split(',')
            ret.append((float(ps[0]),float(ps[1]),float(ps[2]),float(ps[3])))
        return self.__removeClosedParams(ret)
    
    def __removeClosedParams(self,params):
        count = len(params)
        current = 0
        while current < count:
            index = current + 1
            a,b,c,d = params[current]
            while index < count:                
                a1,b1,c1,d1 = params[index]
                if abs(a - a1) < 0.1 and abs(b - b1) < 3 and abs(c - c1) < 0.1 and abs(d - d1) < 3:
                    del params[index]
                    count -= 1
                else:
                    index += 1
            current += 1
        return params
    